//
//  CNPullDownRefreshView.swift
//  Ccweibo
//
//  Created by 陈锦聪 on 16/3/28.
//  Copyright © 2016年 Coco. All rights reserved.
//

import UIKit

private var pullDownRefreshKey = "pullDownRefreshKey"

extension UIScrollView {
    // runtime动态添加属性
    private var pullDownRefreshView: CNPullDownRefreshView {
        get {
            // 动态关联对象(在'self'上根据'key'来获取对象)
            if let refreshView = objc_getAssociatedObject(self, &pullDownRefreshKey) as? CNPullDownRefreshView {
                // 取得所需对象
                return refreshView
            } else {
                // 没有对应对象则创建
                let refreshView = CNPullDownRefreshView()
                self.addSubview(refreshView)
                // 这里会调用set方法
                self.pullDownRefreshView = refreshView
                return refreshView
            }
        }        
        set {
            // 将新创建的对象(newValue)关联到'self'上
            objc_setAssociatedObject(self, &pullDownRefreshKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    func addPullToRefreshHandler(handler: (() -> ())?) {
        pullDownRefreshView.pullToRefreshHandler = handler
    }
    func scrollViewStartRefreshing() {
        pullDownRefreshView.startRefreshing()
    }
    func scrollViewEndRefreshing() {
        pullDownRefreshView.endRefreshing()
    }
}

private let refreshViewHeight: CGFloat = 60

enum CNRefreshControlStatus: Int {
    case Normal             // 下拉刷新
    case PullToRefresh      // 释放刷新
    case Refreshing         // 正在刷新
}

class CNPullDownRefreshView: UIView {
    /// 当前刷新状态
    private var currentStatus: CNRefreshControlStatus = .Normal {
        didSet {
            switch currentStatus {
            case .Normal:
                // 上个状态是‘正在刷新’,需要收起刷新视图
                if previousStatus == .Refreshing {
                    loadingView.layer.removeAnimationForKey("rotation")
                    arrowView.hidden = false
                    loadingView.hidden = true
                    UIView.animateWithDuration(defaultDuration, animations: { () -> Void in
                        self.scrollView.contentInset.top -= refreshViewHeight
                    })
                }
                messageLabel.text = "下拉刷新"
                UIView.animateWithDuration(defaultDuration, animations: { () -> Void in
                    self.arrowView.transform = CGAffineTransformIdentity
                })
            case .PullToRefresh:
                messageLabel.text = "释放刷新"
                UIView.animateWithDuration(defaultDuration, animations: { () -> Void in
                    self.arrowView.transform = CGAffineTransformMakeRotation(CGFloat(M_PI))
                })
            case .Refreshing:
                arrowView.hidden = true
                loadingView.hidden = false
                messageLabel.text = "正在刷新..."
                let animation = CABasicAnimation(keyPath: "transform.rotation")
                animation.duration = 1.0
                animation.toValue = M_PI * 2
                animation.repeatCount = MAXFLOAT
                // key有值时,动画不会叠加
                loadingView.layer.addAnimation(animation, forKey: "rotation")
                UIView.animateWithDuration(defaultDuration, animations: { () -> Void in
                    
                    self.scrollView.contentInset.top += refreshViewHeight

                    }, completion: { (_) -> Void in
                        self.pullToRefreshHandler?()
                })
            }
            // 设置当前状态为上个状态
            previousStatus = currentStatus
        }
    }
    // 上个状态
    private var previousStatus: CNRefreshControlStatus = .Normal
    // 父控件(默认为强引用,使用'weak')
    private weak var scrollView: UIScrollView! // 隐式拆包(使用时不需要强制拆包)
    // 刷新操作
    var pullToRefreshHandler: (() -> ())?
    // 开始刷新
    func startRefreshing() {
        currentStatus = .Refreshing
    }
    // 结束刷新
    func endRefreshing() {
        currentStatus = .Normal
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override init(frame: CGRect) {
        // size固定
        let newFrame = CGRect(x: 0, y: -refreshViewHeight, width: UIScreen.width, height: refreshViewHeight)
        super.init(frame: newFrame)
        prepareUI()
    }
    // 移除通知
    deinit {
        scrollView.removeObserver(self, forKeyPath: "contentOffset")
    }
    
    private func prepareUI() {
//        backgroundColor = UIColor.blueColor()
        addSubview(loadingView)
        addSubview(arrowView)
        addSubview(messageLabel)
        
        loadingView.hidden = true
        
        loadingView.translatesAutoresizingMaskIntoConstraints = false
        arrowView.translatesAutoresizingMaskIntoConstraints = false
        messageLabel.translatesAutoresizingMaskIntoConstraints = false
        
        addConstraint(NSLayoutConstraint(item: loadingView, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: -30))
        addConstraint(NSLayoutConstraint(item: loadingView, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0))
        
        addConstraint(NSLayoutConstraint(item: arrowView, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: loadingView, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0))
        addConstraint(NSLayoutConstraint(item: arrowView, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: loadingView, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0))
        
        addConstraint(NSLayoutConstraint(item: messageLabel, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: arrowView, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: 8))
        addConstraint(NSLayoutConstraint(item: messageLabel, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: arrowView, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0))
        
    }
    // view即将添加到父控件(父控件调用addSubView触发)
    override func willMoveToSuperview(newSuperview: UIView?) {
        super.willMoveToSuperview(newSuperview)
        
        if let superView = newSuperview as? UIScrollView {
            scrollView = superView
            scrollView.addObserver(self, forKeyPath: "contentOffset", options: NSKeyValueObservingOptions.New, context: nil)
        }
    }
    
    override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
//        CNPrint(item: "- \(scrollView.contentOffset)")
        // 正在拖动状态
        if scrollView.dragging {
            
            if currentStatus == .PullToRefresh && scrollView.contentOffset.y > -(scrollView.contentInset.top + refreshViewHeight) {
                currentStatus = .Normal
//                CNPrint(item: "StatusNormal")
            } else if currentStatus == .Normal && scrollView.contentOffset.y <= -(scrollView.contentInset.top + refreshViewHeight) {
                currentStatus = .PullToRefresh
//                CNPrint(item: "StatusPullToRefresh")
            }
        } else if currentStatus == .PullToRefresh { // 处于‘释放刷新’时松手,进入‘正在刷新’
            currentStatus = .Refreshing
//            CNPrint(item: "StatusRefreshing")
        }
    }
    
    // MARK: - lazyLoad
    private lazy var arrowView: UIImageView = UIImageView(image: UIImage(named: "tableview_pull_refresh"))
    
    private lazy var loadingView: UIImageView = UIImageView(image: UIImage(named: "tableview_loading"))
    
    private lazy var messageLabel: UILabel = {
        
        let label = UILabel()
        label.font = UIFont.systemFontOfSize(textFontLarge)
        label.textColor = UIColor.darkGrayColor()
        label.text = "下拉刷新"
        label.sizeToFit()
        return label
    }()

}

